#include"socket.hpp"
#include<sys/epoll.h>

#define BACK_LOG 5
#define SIZE 256
#define MAX_NUM 64
class EpollServer
{
private:
    int _listen_sock;
    int _port;
    int _epfd;
public:
    EpollServer(int port):_port(port)
    {}
    void InitEpollServer()
    {
        _listen_sock = Socket::Socketcreate();
        Socket::Socketbind(_listen_sock,_port);
        Socket::Socketlisten(_listen_sock,BACK_LOG);

        _epfd = epoll_create(SIZE);
        if(_epfd < 0)
        {
            perror("epoll_create");
            exit(5);
        }
    }
    ~EpollServer()
    {
        if(_listen_sock>=0)
        {
            close(_listen_sock);
        }
        if(_epfd>=0)
        {
            close(_epfd);
        }
    }
    void Run()
    {
        AddEvent(_listen_sock,EPOLLIN);
        for(;;)
        {
            struct epoll_event revs[MAX_NUM];
            int num=epoll_wait(_epfd,revs,MAX_NUM,-1);
            if(num < 0)
            {
                std::cerr<<"epoll_wait error"<<std::endl;
                continue;
            }
            else if(num == 0)
            {
                std::cout<<"timeout"<<std::endl;
                continue;
            }
            else
            {
                HandlerEvent(revs,num);
            }
        }
    }
    void HandlerEvent(struct epoll_event revs[],int num)
    {
        for(int i=0;i<num;++i)
        {
            int fd=revs[i].data.fd;
            if(fd == _listen_sock&&revs[i].events&EPOLLIN)
            {
                struct sockaddr_in peer;
                memset(&peer,0,sizeof(peer));
                socklen_t len = sizeof(peer);
                int sock = accept(_listen_sock,(struct sockaddr*)&peer,&len);
                if(sock < 0)
                {
                    std::cerr<<"accept error"<<std::endl;
                    continue;
                }
                std::string peer_ip= inet_ntoa(peer.sin_addr);
                int peer_port = ntohs(peer.sin_port);
                std::cout<<"get a new link["<<peer_ip<<":"<<peer_port<<"]"<<std::endl;
                AddEvent(sock,EPOLLIN);
            }
            else if(revs[i].events&EPOLLIN)
            {
                char buf[64];
                ssize_t size=recv(fd,buf,sizeof(buf)-1,0);
                if(size > 0)
                {
                    buf[size] = '\0';
                    std::cout<<"echo#"<<buf<<std::endl;
                }
                else if(size == 0)
                {

                    std::cout<<"client close"<<std::endl;
                    close(fd);
                    DelEvent(fd);
                }
                else
                {
                    std::cerr<<"recv error"<<std::endl;
                    close(fd);
                    DelEvent(fd);
                }
            }
        }
    }
private:
    void AddEvent(int fd,uint32_t events)
    {
        struct epoll_event ev;
        ev.events = events;
        ev.data.fd = fd;

        epoll_ctl(_epfd,EPOLL_CTL_ADD,fd,&ev);
    }
    void DelEvent(int sock)
    {
        epoll_ctl(_epfd,EPOLL_CTL_DEL,sock,NULL);
    }
};
